home *** CD-ROM | disk | FTP | other *** search
- /*
- File: BackTalk.c
-
- Contains: Source to BackTalk!, part of MacHack '93 entry "MSM 3k"
-
- Written by: Bill Britton, John Arkley, and Jorg Brown
-
- */
-
- #undef SystemSevenOrLater
- #define SystemSevenOrLater 1
-
- #include <diskinit.h>
- #include <errors.h>
- #include <resources.h>
- #include <processes.h>
- #include <fixmath.h>
- #include <GestaltEqu.h>
- #include "Speech.h"
- #include <Sound.h>
-
- typedef unsigned char uchar;
- typedef unsigned short ushort;
- typedef unsigned long ulong;
-
- #define kOSEvent app4Evt /* event used by MultiFinder */
- #define kSuspendResumeMessage 1 /* high byte of suspend/resume event message */
- #define kResumeMask 1 /* bit of message field for resume vs. suspend */
- #define kMouseMovedMessage 0xFA /* high byte of mouse-moved event message */
- #define kNoEvents 0 /* no events mask */
-
- #define rMenuBar 128
-
- #define mApple 128
- #define iAbout 1
-
- #define mFile 129
- #define iNoCmnt 1
- #define iQuit 3
-
- #define mVoice 130
- #define iPrefs 1
-
- #define kMaxVoices 40
-
- Boolean gInBackground; /* maintained by Initialize and DoEvent */
-
- /* gSpeechChan is a global speech channel which can be used for speaking */
- /* gSpeechStr is a global pascal string which can be used for speech */
- /* gSpeechErr is a global error return which can be latched if desired */
-
- SpeechChannel gSpeechChan = NULL;
- Str255 gSpeechStr = "\pMST3000";
- uchar gTextBuf [4096] = {0};
- ushort gTextBufLen = 0;
- OSErr gSpeechErr = noErr;
-
- VoiceSpec gVspec[kMaxVoices];
- short gVoiceSel;
- short gVoiceCount = 0;
- Fixed gSpeechRate = 0;
-
- ProcessSerialNumber gOurPSN;
-
- Boolean gNoComment = false; /* it is possible to have the app not talk via menu selection */
- /* this was done because we wanted to be running during other hacks */
- /* and we might get too obnoxious for some */
-
- ulong gLastSpeak = 0;
-
- extern void _DataInit( void );
- extern pascal OSErr SM_InitializeSpeechManager( void ); /* SPEECH MANAGER: INIT startup -- allocates globals, installs dispatcher */
-
- void DoPrefs( void );
- void Initialize( void );
- void DoIdle( void );
- void EventLoop( void );
- void DoActivate( WindowPtr fWind, Boolean becomingActive );
- void DoMenuCommand( long menuResult );
- void SaySomething( char *sayThis, Boolean regardless );
- void DoUpdate( WindowPtr upWind );
- void DoAbout( void );
- void StartupSpeech( void );
- void Terminate( void );
- void DoEvent( EventRecord *event );
- void DrawMST3( void );
- void DoNoComment( void );
- void AdjustMenus( void );
- void MST3_ChangeRate (Fixed newRate);
- void MST3_ChangePitch (long newPitch);
- void MST3_ChangeVoiceSel (long newVoice);
-
-
-
- /* Define HiWrd and LoWrd macros for efficiency. */
- #define HiWrd(aLong) (((aLong) >> 16) & 0xFFFF)
- #define LoWrd(aLong) ((aLong) & 0xFFFF)
-
-
- typedef struct KeyMapp {
- short wasted;
- short wasted2;
- short wasted3;
- short command : 1;
- short : 5;
- short space : 1;
- short tab : 1;
- short : 4;
- short control : 1;
- short option : 1;
- short capslock : 1;
- short shift : 1;
- } KeyMapp;
-
- #define KM (*(KeyMapp *)0x174)
-
- void DrawMST3( void )
- {
- /* we used this to convert the PICT rsrc to a bitmap while writing the hack */
-
- PicHandle pHdl;
- WindowPtr tWind;
- Rect tRect,wRect;
- OSErr iErr;
- RgnHandle mstRgn;
- BitMap bm, oldbm;
- GrafPort bmPort;
-
- if ( KM.option ) {
- pHdl = (PicHandle)GetResource( 'PICT', 0 );
- if ( pHdl ) {
- tRect = (*pHdl)->picFrame;
- OffsetRect(&tRect, 0 - tRect.left, 0 - tRect.top);
- OpenPort(&bmPort);
- bm.baseAddr = NewPtrClear(128000);
- bm.bounds = tRect;
- bm.bounds.right += 16;
- bm.bounds.right &= ~15;
- bm.rowBytes = bm.bounds.right / 8;
- SetPortBits(&bm);
- DrawPicture(pHdl,&tRect);
- mstRgn = NewRgn();
- iErr = BitMapToRegion(mstRgn,&bm);
- AddResource((Handle)mstRgn,'mstp',0,"\pMST3000");
- if ( !ResError() ) {
- WriteResource( (Handle)mstRgn );
- UpdateResFile( CurResFile() );
- }
-
- ClosePort( &bmPort );
- DisposeRgn( mstRgn );
- }
- }
- } // DrawMST3()
-
-
- void Initialize( void )
- {
- long total, contig;
- long response;
- EventRecord event;
- Handle menuBar;
- short count;
- OSErr iErr;
- long result;
- ProcessSerialNumber aPSN;
-
- gInBackground = false;
-
- InitGraf((Ptr) &qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- InitCursor();
-
- for (count = 1; count <= 3; count++)
- EventAvail(everyEvent, &event);
-
- PurgeSpace(&total, &contig);
-
- // got the speech mgr?
-
- count = Gestalt(gestaltSpeechAttr, &response);
- if ( response ) {
- menuBar = GetNewMBar(rMenuBar); /* read menus into menu bar */
- SetMenuBar(menuBar); /* install menus */
- DisposHandle(menuBar);
- AddResMenu(GetMHandle(mApple), 'DRVR'); /* add DA names to Apple menu */
- DrawMenuBar();
- }
-
- // this may come in handy someday
- iErr = GetCurrentProcess( &gOurPSN );
-
- // politely send us to the background
- aPSN.highLongOfPSN = 0;
- aPSN.lowLongOfPSN = kNoProcess;
- iErr = GetNextProcess( &aPSN );
- while ( true ) {
- if ( aPSN.lowLongOfPSN != gOurPSN.lowLongOfPSN )
- break;
- else if ( iErr = GetNextProcess( &aPSN ) )
- break;
- }
- iErr = SetFrontProcess( &aPSN );
-
- } // Initialize()
-
-
- main()
- {
- MaxApplZone(); /* expand the heap so code segments load at the top */
-
- Initialize(); /* initialize the program */
-
- StartupSpeech();
-
- EventLoop(); /* call the main event loop */
- }
-
- SndChannel sndZero;
- SndChannel ChanSpace, *myChan;
-
- void DoIdle( void )
- {
- #define JORG_SELECTOR 'MSM3'
- #define ARE_WE_INTERVAL 18000 // 5 minutes
-
- #define MSM_STR_ID 128
- #define PREFS_IND 1
- #define SUSPEND_IND 2
-
- // event-based messages - sent from the MSM 3K INIT
- #define EB_STR_ID 129
- #define B_HELP 1 // User tried to turn on balloon help ("Mommy, not the clown suit!")
- #define TRASH_WIMP 2 // User turned on trash warnings ("What a wimp!")
- #define GATES_OF_HELL 3 // User ran a Microsoft product ("Welcome to MS technical support. Please hold for one hour")
- #define CLEANUP 4 // User chose "Clean Up Window" ("This will simplify everything")
- #define ERASEDISK 5 // User chose "Erase Disk" in the Finder ("Watch out, he's got a gun!")
- #define DONTTREADONME 6 // Clicking on the heads ("STOP TOUCHING ME")
- #define INSIDEADIALOG 7 // Inside a dialog too long ("Take your time, we're not going anywhere")
- #define MOVEMOUSELEFT 8 // To the right of a dialog too long ("Left turn, Clyde")
- #define MOVEMOUSERIGHT 9 // TO the left of a dialog too long ("Concentrate on the RIGHT")
- #define MOVEMOUSEDOWN 10 // On top of a dialog too long ("Looks like you're right on top of things!")
- #define MOVEMOUSEUP 11 // Under a dialog too long ("Look up! It's a plane! It's a bird! It's a dieolog box!")
- #define MAKINCOPIES 12 // Finder's makin' copies ("Take your time, we're not in aisle seats!")
-
- // time-based messages
- #define TB_STR_ID 130
- #define MAX_TB_STRINGS 3
- #define FUN_YET 1
- #define PUMA 2
- #define DUMB_HACK 3
-
- OSErr iErr;
- pascal OSErr (*MSM_Gestalt)(OSType selector, long *response);
- long speechCode;
- Handle snd;
- SCStatus scs;
- short err;
-
- if (myChan) {
- if (SndChannelStatus(myChan, sizeof(scs), &scs) != noErr) return;
- if (scs.scChannelBusy) return;
- SndDisposeChannel(myChan, FALSE);
- myChan = 0;
- }
- // we want to always check the selector as this clears it if non-nil
- if ( (Gestalt( JORG_SELECTOR, (void *)&MSM_Gestalt ) == noErr) && !SpeechBusy() ) {
- if (MSM_Gestalt('back', &speechCode) == noErr) {
- if ( speechCode ) {
- if (snd = Get1Resource('snd ', 256 + speechCode)) {
- ChanSpace = sndZero;
- ChanSpace.qLength = stdQLength;
- myChan = &ChanSpace;
- err = SndNewChannel(&myChan, 0, initMono, 0);
- if (err == noErr) {
- err = SndPlay(myChan, snd, TRUE);
- } else myChan = 0;
- } else {
- GetIndString( gSpeechStr, EB_STR_ID, speechCode );
- SaySomething( (char *)gSpeechStr, false );
- }
- }
- }
- } else if ( ((TickCount() - gLastSpeak) > ARE_WE_INTERVAL) && !SpeechBusy() ) {
- gLastSpeak = TickCount();
- GetIndString( gSpeechStr, TB_STR_ID, (gLastSpeak % MAX_TB_STRINGS) + 1 );
- SaySomething( (char *)gSpeechStr, false );
- }
- } // DoIdle()
-
-
- void EventLoop( void )
- {
- Boolean gotEvent;
- EventRecord event;
-
- do {
- gotEvent = WaitNextEvent(everyEvent, &event, 0, (RgnHandle)nil);
-
- if ( gotEvent ) {
- DoEvent(&event);
- } else {
- DoIdle();
- }
- } while ( true ); /* loop forever; we quit via ExitToShell */
-
- } /*EventLoop*/
-
-
- void DoEvent( EventRecord *event )
- {
- short part, err;
- WindowPtr window;
- uchar key;
- Point aPoint;
-
- switch ( event->what ) {
- case nullEvent:
- /* we idle for null/mouse moved events ands for events which aren’t
- ours (see EventLoop) */
- DoIdle();
- break;
- case mouseDown:
- part = FindWindow(event->where, &window);
- switch ( part ) {
- case inMenuBar: /* process a mouse menu command (if any) */
- AdjustMenus();
- DoMenuCommand(MenuSelect(event->where));
- break;
- case inSysWindow: /* let the system handle the mouseDown */
- SystemClick(event, window);
- break;
- }
- break;
- case keyDown:
- case autoKey: /* check for menukey equivalents */
- key = (uchar) event->message & charCodeMask;
- if ( event->modifiers & cmdKey ) { /* Command key down */
- if ( event->what == keyDown ) {
- DoMenuCommand(MenuKey(key));
- }
- }
- break;
- case activateEvt:
- DoActivate((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
- break;
- case updateEvt:
- DoUpdate((WindowPtr) event->message);
- break;
- case diskEvt:
- if ( HiWord(event->message) != noErr ) {
- SetPt(&aPoint, 50, 50);
- err = DIBadMount(aPoint, event->message);
- }
- break;
- case kOSEvent:
- /* 1.02 - must BitAND with 0x0FF to get only low byte */
- switch ((event->message >> 24) & 0x0FF) { /* high byte of message */
- case kMouseMovedMessage:
- DoIdle(); /* mouse-moved is also an idle event */
- break;
- case kSuspendResumeMessage: /* suspend/resume is also an activate/deactivate */
- gInBackground = (event->message & kResumeMask) == 0;
- DoActivate(FrontWindow(), !gInBackground);
- break;
- }
- break;
- }
- } /*DoEvent*/
-
-
- void DoActivate( WindowPtr fWind, Boolean becomingActive )
- {
- if ( becomingActive ) SetCursor( &qd.arrow );
- }
-
- void AdjustMenus( void )
- {
- MenuHandle mHdl;
- short i;
-
- CheckItem( GetMHandle( mFile ), iNoCmnt, gNoComment );
-
- mHdl = GetMHandle( mVoice );
- for ( i=3 ; i<=gVoiceCount ; i++ )
- CheckItem( mHdl, i, false );
-
- CheckItem( mHdl, gVoiceSel+2, true );
-
- }
-
- void DoMenuCommand( long menuResult )
- {
- short menuID, menuItem;
- short daRefNum;
- Str255 daName;
- WindowPtr window;
- Handle aHandle;
- OSErr err;
-
- window = FrontWindow();
- menuID = HiWord(menuResult); /* use macros for efficiency to... */
- menuItem = LoWord(menuResult); /* get menu item number and menu number */
- switch ( menuID ) {
- case mApple:
- switch ( menuItem ) {
- case iAbout: /* bring up alert for About */
- DoAbout();
- break;
- default: /* all non-About items in this menu are DAs et al */
- /* type Str255 is an array in MPW 3 */
- GetItem(GetMHandle(mApple), menuItem, daName);
- daRefNum = OpenDeskAcc(daName);
- break;
- }
- break;
- case mFile:
- switch ( menuItem ) {
- case iNoCmnt:
- DoNoComment();
- break;
- case iQuit:
- Terminate();
- break;
- }
- break;
-
- case mVoice: /* SPEECH MANAGER */
- if (menuItem)
- {
- if (gSpeechChan)
- {
- err = DisposeSpeechChannel(gSpeechChan);
- gSpeechChan = NULL;
- }
- if ( menuItem == iPrefs )
- DoPrefs();
- else
- gVoiceSel = menuItem-2;
- }
- break;
- }
- HiliteMenu(0); /* unhighlight what MenuSelect (or MenuKey) hilited */
- }
-
- void DoUpdate( WindowPtr upWind )
- {
- }
-
- void DoAbout( void )
- {
- DialogPtr theDLOG;
- short dItem = 0;
-
- if ( theDLOG = GetNewDialog( 128, nil, (WindowPtr)-1 ) ) {
- ModalDialog( nil, &dItem );
- DisposeDialog( theDLOG );
- }
- }
-
- void StartupSpeech( void )
- {
- OSErr err;
- short voiceCount;
- short i;
- VoiceDescription vd;
- MenuHandle voiceMenu;
- NumVersion ver = SpeechManagerVersion();
-
- #ifndef forRez
- enum {development=0x20, alpha=0x40, beta=0x60, final=0x80, release=0x80};
- #endif
-
- #define kMgrMajorVersion 1 /* 8-bits */
- #define kMgrMinorVersion 0 /* 4-bits */
- #define kMgrBugFixVersion 0 /* 4-bits */
- #define kMgrDevelopmentStage alpha /* 8-bits */
- #define kMgrNonRelVersion 2 /* 8-bits */
-
- #define kSpeechManagerVersion ((kMgrMajorVersion << 24) \
- | (kMgrMinorVersion << 20) \
- | (kMgrBugFixVersion << 16) \
- | (kMgrDevelopmentStage << 8) \
- | (kMgrNonRelVersion))
-
- voiceMenu = GetMHandle (mVoice);
-
- err = CountVoices(&voiceCount);
- gVoiceCount = voiceCount;
- if (voiceCount > kMaxVoices-1) voiceCount = kMaxVoices-1;
- for (i = 1; i <= voiceCount; i++) {
- err = GetIndVoice(i, &gVspec[i]);
-
- if ( true || ((*( ulong *) (&ver)) >= kSpeechManagerVersion)) {
- // newer versions expect you to pass length in parameter list
- err = GetVoiceDescription(&gVspec[i], &vd, sizeof(VoiceDescription));
- } else {
- //vd.length = sizeof(VoiceDescription); // early versions require you to set length field
- //err = GetVoiceDescription(&gVspec[i], &vd);
- }
- AppendMenu (voiceMenu, vd.name);
- }
- gVoiceSel = 0; // use Default voice
- } // StartupSpeech()
-
-
- void SaySomething( char *sayThis, Boolean regardless )
- {
- /*
- note that the STR# resources use the first three chars to define
- voice, speech rate, and speech pitch respectively. These are all based
- on some rather crude scales that just get the job done.
- */
-
- OSErr iErr;
-
- if ( regardless || !gNoComment ) {
-
- if ( !gSpeechChan ) {
- if (gVoiceSel == 0)
- iErr = NewSpeechChannel(0, &gSpeechChan);
- else
- iErr = NewSpeechChannel(&gVspec[gVoiceSel], &gSpeechChan);
- }
-
- if ( gSpeechChan ) {
- MST3_ChangeVoiceSel( sayThis[1] - '@' );
- MST3_ChangeRate( 0x00940000 + ((sayThis[2] - '0') * 0x00020000) );
- MST3_ChangePitch( sayThis[3] - '0' );
- iErr = SetSpeechInfo(gSpeechChan, soRate, &gSpeechRate);
- iErr = SpeakText(gSpeechChan, (Ptr)&sayThis[4], sayThis[0]-3);
- }
- }
- } // SaySomething()
-
-
- void DoPrefs( void )
- {
- GetIndString( gSpeechStr, MSM_STR_ID, PREFS_IND );
- SaySomething( (char *)gSpeechStr, true );
- }
-
- void DoNoComment( void )
- {
- gNoComment = !gNoComment;
- if ( gNoComment ) {
- GetIndString( gSpeechStr, MSM_STR_ID, SUSPEND_IND );
- SaySomething( (char *)gSpeechStr, true );
- }
- }
-
- void Terminate( void )
- {
- // dump any data???
- while (myChan) DoIdle();
- DrawMST3();
- ExitToShell();
- }
-
- void MST3_ChangeRate (Fixed newRate)
- {
- Fixed oldRate;
- OSErr err;
-
- if (gSpeechChan) {
- err = GetSpeechRate(gSpeechChan, &oldRate);
- err = SetSpeechRate(gSpeechChan, newRate);
- gSpeechRate = newRate; // save the new rate
- }
- }
-
- void MST3_ChangePitch (long newPitch)
- {
- Fixed thePitch;
- OSErr err;
-
- if (gSpeechChan) {
- thePitch = Long2Fix(newPitch*10);
- err = SetSpeechPitch( gSpeechChan, thePitch);
- }
- }
-
- void MST3_ChangeVoiceSel(long newVoice)
- {
- if (newVoice <= gVoiceCount && newVoice > 0) gVoiceSel = newVoice;
-
- }
-